home *** CD-ROM | disk | FTP | other *** search
/ PC Format (PL) 2008 February / PC_Format_022008.iso / Internet / Mozilla Thunderbird wtyczki / lightning-0.7-tb-win.xpi / components / calItipEmailTransport.js < prev    next >
Encoding:
JavaScript  |  2007-03-07  |  16.5 KB  |  429 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Simdesk Technologies code.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Simdesk Technologies.
  18.  * Portions created by the Initial Developer are Copyright (C) 2007
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   Clint Talbert <ctalbert.moz@gmail.com>
  23.  *   Matthew Willis <lilmatt@mozilla.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. /**
  40.  * Constructor of calItipEmailTransport object
  41.  */
  42. function calItipEmailTransport() {
  43.     this.wrappedJSObject = this;
  44.     this._initEmailTransport();
  45. }
  46.  
  47. calItipEmailTransport.prototype = {
  48.  
  49.     QueryInterface: function cietQI(aIid) {
  50.         if (!aIid.equals(Components.interfaces.nsISupports) &&
  51.             !aIid.equals(Components.interfaces.calIItipTransport))
  52.         {
  53.             throw Components.results.NS_ERROR_NO_INTERFACE;
  54.         }
  55.  
  56.         return this;
  57.     },
  58.  
  59.     mHasXpcomMail: false,
  60.     mAccountMgrSvc: null,
  61.     mDefaultAccount: null,
  62.     mDefaultSmtpServer: null,
  63.  
  64.     mDefaultIdentity: null,
  65.     get defaultIdentity() {
  66.         return this.mDefaultIdentity.email;
  67.     },
  68.  
  69.     mSenderAddress: null,
  70.     get senderAddress() {
  71.         return this.mSenderAddress;
  72.     },
  73.     set senderAddress(aValue) {
  74.         return (this.mSenderAddress = aValue);
  75.     },
  76.  
  77.     get type() {
  78.         return "email";
  79.     },
  80.  
  81.     /**
  82.      * Pass the transport an itipItem and have it figure out what to do with
  83.      * it based on the itipItem's methods.
  84.      */
  85.     simpleSendResponse: function cietSSR(aItem) {
  86.         var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"].
  87.                   getService(Components.interfaces.nsIStringBundleService);
  88.         var sb = sbs.createBundle("chrome://lightning/locale/lightning.properties");
  89.  
  90.         var itemList = aItem.getItemList({ });
  91.  
  92.         // Get my participation status
  93.         var myPartStat;
  94.         var foundMyself = false;
  95.         var attendee = itemList[0].getAttendeeById("mailto:" +
  96.                                                    this.mDefaultIdentity.email);
  97.         if (attendee) {
  98.             myPartStat = attendee.participationStatus;
  99.             foundMyself = true;
  100.         }
  101.  
  102.         if (!foundMyself) {
  103.             // I didn't find myself in the attendee list.
  104.             //
  105.             // This can happen when invitations are sent to email aliases
  106.             // instead of mDefaultIdentity.email (ex: lilmatt vs. mwillis),
  107.             // or if an invitation is sent to a listserv.
  108.             //
  109.             // We'll need to make more decisions regarding how to handle this
  110.             // in the future. (ex: Prompt? Find myself in list?)  For now, we
  111.             // just don't send a response.
  112.             return;
  113.         }
  114.  
  115.         var name = this.mDefaultIdentity.email;
  116.         if (this.mDefaultIdentity.fullName) {
  117.             name = this.mDefaultIdentity.fullName + " <" + name + ">";
  118.         }
  119.  
  120.         var summary;
  121.         if (itemList[0].getProperty("SUMMARY")) {
  122.             summary = itemList[0].getProperty("SUMMARY");
  123.         } else {
  124.             summary = "";
  125.         }
  126.         var subj = sb.formatStringFromName("itipReplySubject", [summary], 1);
  127.  
  128.         // Generate proper body from my participation status
  129.         var body;
  130.         dump("\n\nthis is partstat: " + myPartStat + "\n");
  131.         if (myPartStat == "DECLINED") {
  132.             body = sb.formatStringFromName("itipReplyBodyDecline",
  133.                                            [name], 1);
  134.         } else {
  135.             body = sb.formatStringFromName("itipReplyBodyAccept",
  136.                                            [name], 1);
  137.         }
  138.  
  139.         var recipients = [itemList[0].organizer];
  140.  
  141.         this.sendItems(recipients.length, recipients, subj, body, aItem);
  142.     },
  143.  
  144.     sendItems: function cietSI(aCount, aRecipients, aSubject, aBody, aItem) {
  145.         LOG("sendItems: Sending Email...");
  146.         if (this.mHasXpcomMail) {
  147.             this._sendXpcomMail(aCount, aRecipients, aSubject, aBody, aItem);
  148.         } else {
  149.             // Sunbird case: Call user's default mailer on system.
  150.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  151.         }
  152.     },
  153.  
  154.     checkForInvitations: function cietCFI(searchStart) {
  155.         // We only need to do trigger a check for incoming invitations if we
  156.         // are not Thunderbird.
  157.         if (!this.mHasXpcomMail) {
  158.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  159.         }
  160.     },
  161.  
  162.     _initEmailTransport: function cietIES() {
  163.         try {
  164.             this.mAccountMgrSvc =
  165.                  Components.classes["@mozilla.org/messenger/account-manager;1"].
  166.                  getService(Components.interfaces.nsIMsgAccountManager);
  167.  
  168.             this.mDefaultAccount = this.mAccountMgrSvc.defaultAccount;
  169.             this.mDefaultIdentity = this.mDefaultAccount.defaultIdentity;
  170.  
  171.             var smtpSvc = Components.classes["@mozilla.org/messengercompose/smtp;1"].
  172.                           getService(Components.interfaces.nsISmtpService);
  173.             this.mSmtpServer = smtpSvc.defaultServer;
  174.  
  175.         } catch (ex) {
  176.             // Then we must resort to operating system specific means
  177.             this.mHasXpcomMail = false;
  178.         }
  179.  
  180.         // But if none of that threw then we can send an email through XPCOM.
  181.         this.mHasXpcomMail = true;
  182.         LOG("initEmailService: hasXpcomMail: " + this.mHasXpcomMail);
  183.     },
  184.  
  185.     _sendXpcomMail: function cietSXM(aCount, aToList, aSubject, aBody, aItem) {
  186.         // Save calItipItem to a temporary file.
  187.         LOG("sendXpcomMail: Creating temp file for attachment.");
  188.         var msgAttachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].
  189.                             createInstance(Components.interfaces.nsIMsgAttachment);
  190.         msgAttachment.url = this._createTempIcsFile(aItem);
  191.         if (!msgAttachment.url) {
  192.             LOG("sendXpcomMail: No writeable path in profile!");
  193.             // XXX Is there an "out of disk space" error?
  194.             throw Components.results.NS_ERROR_FAILURE;
  195.         }
  196.  
  197.         msgAttachment.name =  "calendar.ics";
  198.         msgAttachment.contentType = "text/calendar";
  199.         msgAttachment.contentTypeParam = "method=" + aItem.responseMethod;
  200.         // Destroy the attachment after sending
  201.         msgAttachment.temporary = true;
  202.  
  203.         // compose fields for message
  204.         var composeFields = Components.classes["@mozilla.org/messengercompose/composefields;1"].
  205.                             createInstance(Components.interfaces.nsIMsgCompFields);
  206.         composeFields.useMultipartAlternative = true;
  207.         composeFields.characterSet = "UTF-8";
  208.         // TODO: xxx make this use the currently selected mail account, if
  209.         // possible, and default to the default account if the selection
  210.         // is unclear.
  211.         var toList = "";
  212.         for each (var recipient in aToList) {
  213.             // Strip leading "mailto:" if it exists.
  214.             var rId = recipient.id.replace(/^mailto:/i, "");
  215.  
  216.             // Prevent trailing commas.
  217.             if (toList.length > 0) {
  218.                 toList += ",";
  219.             }
  220.  
  221.             // Add this recipient id to the list.
  222.             toList += rId;
  223.         }
  224.         composeFields.to = toList;
  225.         composeFields.from = this.mDefaultIdentity.email;
  226.         composeFields.replyTo = this.mDefaultIdentity.replyTo;
  227.         composeFields.subject = aSubject;
  228.         composeFields.body = aBody;
  229.         composeFields.addAttachment(msgAttachment);
  230.  
  231.         // Message paramaters
  232.         var composeParams = Components.classes["@mozilla.org/messengercompose/composeparams;1"].
  233.                             createInstance(Components.interfaces.nsIMsgComposeParams);
  234.         composeParams.composeFields = composeFields;
  235.         // TODO: xxx: Make this a pref or read the default pref
  236.         composeParams.format = Components.interfaces.nsIMsgCompFormat.PlainText;
  237.         composeParams.type = Components.interfaces.nsIMsgCompType.New;
  238.  
  239.         var composeService = Components.classes["@mozilla.org/messengercompose;1"].
  240.                              getService(Components.interfaces.nsIMsgComposeService);
  241.         switch (aItem.autoResponse) {
  242.             case (Components.interfaces.calIItipItem.USER):
  243.                 LOG("sendXpcomMail: Found USER autoResponse type.");
  244.  
  245.                 // Open a compose window
  246.                 var url = "chrome://messenger/content/messengercompose/messengercompose.xul"
  247.                 composeService.OpenComposeWindowWithParams(url, composeParams);
  248.                 break;
  249.             case (Components.interfaces.calIItipItem.AUTO):
  250.                 LOG("sendXpcomMail: Found AUTO autoResponse type.");
  251.  
  252.                 var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
  253.                          getService(Components.interfaces.nsIWindowWatcher);
  254.                 var win = ww.activeWindow;
  255.                 var msgCompose = Components.classes["@mozilla.org/messengercompose/compose;1"].
  256.                                  createInstance(Components.interfaces.nsIMsgCompose);
  257.                 msgCompose.Initialize(win, composeParams);
  258.                 // Fourth param is message window, fifth param is progress.
  259.                 // TODO: xxx decide on whether or not we want progress window
  260.                 msgCompose.SendMsg(Components.interfaces.nsIMsgCompDeliverMode.Now,
  261.                                    this.mDefaultIdentity,
  262.                                    this.mDefaultAccount.key,
  263.                                    null,
  264.                                    null);
  265.                 break;
  266.             case (Components.interfaces.calIItipItem.NONE):
  267.                 LOG("sendXpcomMail: Found NONE autoResponse type.");
  268.  
  269.                 // No response
  270.                 break;
  271.             default:
  272.                 // Unknown autoResponse type
  273.                 throw new Error("sendXpcomMail: " +
  274.                                 "Unknown autoResponse type: " +
  275.                                 aItem.autoResponse);
  276.         }
  277.     },
  278.  
  279.     _createTempIcsFile: function cietCTIF(aItem) {
  280.         var path;
  281.         var itemList = aItem.getItemList({ });
  282.         // This is a workaround until bug 353369 is fixed.
  283.         // Without it, we cannot roundtrip the METHOD property, so we must
  284.         // re-add it to the ICS data as we serialize it.
  285.         //
  286.         // Look at the implicit assumption in the code at:
  287.         // http://lxr.mozilla.org/seamonkey/source/calendar/base/src/calEvent.js#162
  288.         // and it's easy to see why.
  289.         itemList[0].setProperty("METHOD", aItem.responseMethod);
  290.         var calText = "";
  291.         for (var i = 0; i < itemList.length; i++) {
  292.             calText += itemList[i].icalString;
  293.         }
  294.  
  295.         LOG("ICS to be emailed: " + calText);
  296.  
  297.         try {
  298.             var dirUtils = Components.classes["@mozilla.org/file/directory_service;1"].
  299.                            createInstance(Components.interfaces.nsIProperties);
  300.             var tempFile = dirUtils.get("TmpD", Components.interfaces.nsIFile);
  301.             tempFile.append("itipTemp");
  302.             tempFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
  303.  
  304.             var outputStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
  305.                                createInstance(Components.interfaces.nsIFileOutputStream);
  306.             var utf8CalText = this._convertFromUnicode("UTF-8", calText);
  307.  
  308.             // Let's write the file - constants from file-utils.js
  309.             const MODE_WRONLY   = 0x02;
  310.             const MODE_CREATE   = 0x08;
  311.             const MODE_TRUNCATE = 0x20;
  312.             outputStream.init(tempFile,
  313.                               MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE,
  314.                               0600, 0);
  315.             outputStream.write(utf8CalText, utf8CalText.length);
  316.             outputStream.close();
  317.  
  318.             var ioService = Components.classes["@mozilla.org/network/io-service;1"].
  319.                             getService(Components.interfaces.nsIIOService);
  320.             path = ioService.newFileURI(tempFile).spec;
  321.         } catch (ex) {
  322.             LOG("createTempItipFile failed! " + ex);
  323.             path = null;
  324.         }
  325.         LOG("createTempItipFile path: " + path);
  326.         return path;
  327.     },
  328.  
  329.     _convertFromUnicode: function cietCFU(aCharset, aSrc) {
  330.         var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
  331.                                createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
  332.         unicodeConverter.charset = aCharset;
  333.         return unicodeConverter.ConvertFromUnicode(aSrc);
  334.     }
  335. };
  336.  
  337.  
  338. /****
  339.  **** module registration
  340.  ****/
  341.  
  342. var calItipEmailTransportModule = {
  343.  
  344.     mCID: Components.ID("{d4d7b59e-c9e0-4a7a-b5e8-5958f85515f0}"),
  345.     mContractID: "@mozilla.org/calendar/itip-transport;1?type=email",
  346.  
  347.     mUtilsLoaded: false,
  348.     loadUtils: function itipEmailLoadUtils() {
  349.         if (this.mUtilsLoaded)
  350.             return;
  351.  
  352.         const jssslContractID = "@mozilla.org/moz/jssubscript-loader;1";
  353.         const jssslIID = Components.interfaces.mozIJSSubScriptLoader;
  354.  
  355.         const iosvcContractID = "@mozilla.org/network/io-service;1";
  356.         const iosvcIID = Components.interfaces.nsIIOService;
  357.  
  358.         var loader = Components.classes[jssslContractID].getService(jssslIID);
  359.         var iosvc = Components.classes[iosvcContractID].getService(iosvcIID);
  360.  
  361.         // Note that unintuitively, __LOCATION__.parent == .
  362.         // We expect to find utils in ./../js
  363.         var appdir = __LOCATION__.parent.parent;
  364.         appdir.append("js");
  365.         var scriptName = "calUtils.js";
  366.  
  367.         var f = appdir.clone();
  368.         f.append(scriptName);
  369.  
  370.         try {
  371.             var fileurl = iosvc.newFileURI(f);
  372.             loader.loadSubScript(fileurl.spec, this.__parent__.__parent__);
  373.         } catch (e) {
  374.             dump("Error while loading " + fileurl.spec + "\n");
  375.             throw e;
  376.         }
  377.  
  378.         this.mUtilsLoaded = true;
  379.     },
  380.     
  381.     registerSelf: function (compMgr, fileSpec, location, type) {
  382.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  383.         compMgr.registerFactoryLocation(this.mCID,
  384.                                         "Calendar iTIP Email Transport",
  385.                                         this.mContractID,
  386.                                         fileSpec,
  387.                                         location,
  388.                                         type);
  389.     },
  390.  
  391.     getClassObject: function (compMgr, cid, iid) {
  392.         if (!cid.equals(this.mCID))
  393.             throw Components.results.NS_ERROR_NO_INTERFACE;
  394.  
  395.         if (!iid.equals(Components.interfaces.nsIFactory))
  396.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  397.  
  398.         this.loadUtils();
  399.  
  400.         return this.mFactory;
  401.     },
  402.  
  403.     mFactory: {
  404.         createInstance: function (outer, iid) {
  405.             if (outer != null)
  406.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  407.             return (new calItipEmailTransport()).QueryInterface(iid);
  408.         }
  409.     },
  410.  
  411.     canUnload: function(compMgr) {
  412.         return true;
  413.     }
  414. };
  415.  
  416. function NSGetModule(compMgr, fileSpec) {
  417.     return calItipEmailTransportModule;
  418. }
  419.  
  420. function LOG(aString) {
  421.     if (!getPrefSafe("calendar.itip.email.log", false)) {
  422.         return;
  423.     }
  424.     var consoleService = Components.classes["@mozilla.org/consoleservice;1"].
  425.                          getService(Components.interfaces.nsIConsoleService);
  426.     consoleService.logStringMessage(aString);
  427.     dump(aString + "\n");
  428. }
  429.